﻿using Me.Framework.ObjFactory;
using Me.Framework.Xml.Base;
using Me.Framework.Xml.XmlAttr;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace Me.Framework.Xml.DeConvert
{
    public class XmlToObj : XmlHelper
    {
        public T ToObj<T>(string uri, string xml)
        {
            //类型判断
            //判断是系统类型 、对象、集合
            Type type = typeof(T);
            if (!CheckIsSysType(type))
            {
                //判断对象是否是根节点
                bool isRootNode = CheckIsRootNode(type);

                //不是系统类型 则创建实例
                T instance = Activator.CreateInstance<T>();
                if (CheckIsCollection(type))
                {
                    //集合
                    XmlNode xn = LoadRootNode(uri, xml);
                    Type singleType = type.GenericTypeArguments.FirstOrDefault();
                    string nodeName = GetNodeAttrName<NodeNameAttribute>(singleType, "Name");
                    if (nodeName == null)
                        nodeName = singleType.Name;
                    XmlNodeList xnList = xn.SelectNodes(nodeName);
                    foreach (XmlNode item in xnList)
                    {
                        (instance as IList).Add(ToObj(singleType,item));
                    }
                }
                else
                {
                    XmlNode xn = LoadRootNode(uri, xml);
                    //对象
                    if (!isRootNode)
                    {
                        string nodeName = GetNodeAttrName<NodeNameAttribute>(type, "Name");
                        if (nodeName == null)
                            nodeName = type.Name;
                        xn = xn.SelectSingleNode(nodeName);
                    }
                    instance = (T)ToObj(type,xn);
                }
                return instance;
            }
            return default(T);
        }

        private object ToObj(Type type, XmlNode xn)
        {
            //创建Type实例
            object obj = Activator.CreateInstance(type, null);
            PropertyInfo[] propertys = type.GetProperties();
            foreach (var property in propertys)
            {
                object val = null;
                //判断是属性 、 节点（单节点、子节点）
                if (CheckIsAttribute(property))
                {
                    //属性
                    val = GetNodeAttrVal(property, xn);
                }
                else
                {
                    //节点
                    val = ToObj(property, xn);
                }
                property.SetValue(obj, Convert.ChangeType(val, property.PropertyType), null);
            }
            return obj;
        }

        #region "=============================获取属性==============================="
        private object GetNodeAttrVal(PropertyInfo property, XmlNode xn)
        {
            string attr = GetNodeAttrName<NodeAttrAttribute>(property, "Name");
            if (attr == null)
                throw new Exception("属性配置错误,请检查模型!");
            object resutl = GetNodeAttrVal(xn, attr);
            return resutl;
        }

        private object GetNodeAttrVal(XmlNode xn, string attributeName)
        {
            object result = xn.Attributes[attributeName].InnerText;
            return result;
        }

        #endregion "=============================获取属性==============================="

        #region "=============================获取节点==============================="
        private object ToObj(PropertyInfo property, XmlNode xn)
        {
            object result = null;
            string nodeName = GetNodeAttrName<NodeNameAttribute>(property, "Name");
            if (nodeName == null)
                nodeName = property.Name;
            //判断是否为System类型
            if (CheckIsSysType(property.PropertyType))
            {
                //System类型
                result = GetNodeVal(xn, nodeName);
            }
            else
            {
                //对象或集合
                result = ToObj(property, xn, nodeName);
            }

            return result;
        }

        private object GetNodeVal(XmlNode xn, string nodeName)
        {
            object resutl = xn.SelectSingleNode(nodeName).InnerText;
            return resutl;
        }

        private object ToObj(PropertyInfo property, XmlNode xn, string nodeName)
        {
            //创建实例 判断类型
            object obj = Activator.CreateInstance(property.PropertyType, null);
            if (CheckIsCollection(obj))
            {
                //集合
                XmlNodeList xnList = xn.SelectNodes(nodeName);
                obj = ToCollection(property, xnList, nodeName);
            }
            else
            {
                //对象
                XmlNode xnChild = xn.SelectSingleNode(nodeName);
                obj = ToObj(property.PropertyType, xnChild);
            }

            return obj;
        }

        private object ToCollection(PropertyInfo property, XmlNodeList xnList, string nodeName)
        {
            object obj = Activator.CreateInstance(property.PropertyType, null);
            object val = null;
            Type singleObjType = property.PropertyType.GenericTypeArguments.FirstOrDefault();
            foreach (XmlNode item in xnList)
            {
                //判断系统类型 还是对象
                if (CheckIsSysType(singleObjType))
                {
                    val = GetNodeVal(item, nodeName);
                }
                else
                {
                    if (CheckIsCollection(singleObjType))
                    {
                        //集合
                        val = ToCollection(singleObjType,xnList);
                    }
                    else
                    {
                        //对象
                        val = ToObj(singleObjType, item);
                    }
                }
                (obj as IList).Add(val);
            }
            return val;
        }

        private object ToCollection(Type type, XmlNodeList xnList)
        {
            object obj = Activator.CreateInstance(type,null);
            string nodeName = GetNodeAttrName<NodeNameAttribute>(type,"Name");
            if (nodeName == null)
                nodeName = type.Name;
            object val = null;
            Type singleType = obj.GetType().GenericTypeArguments.FirstOrDefault();

            foreach (XmlNode item in xnList)
            {
                if (CheckIsSysType(singleType))
                {
                    //系统类型
                    val = GetNodeVal(item, nodeName);
                }
                else
                {
                    if (CheckIsCollection(singleType))
                    {
                        XmlNodeList xnChild = item.SelectNodes(nodeName);
                        val = ToCollection(singleType,xnChild);
                    }
                    else
                    {
                        val = ToObj(singleType,item);
                    }
                }
                (obj as IList).Add(val);
            }

            return obj;
        }
        #endregion "=============================获取节点==============================="
    }
}
